package com.aliang.book_java1.po.java8的流库;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 从迭代到流的操作
 */
public class java_stream_01 {
    static String cotents;

    static {
        try {
            cotents = new String(Files.readAllBytes(Paths.get("E:\\MY_FUTURE\\FJ_FLIE\\alice.txt")), StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        //getCountFromFile();
        creatStream();
    }

    //1.1从迭代到流的操作
    public static void  getCountFromFile() throws IOException {
        String cotents=new String(Files.readAllBytes(Paths.get("E:\\MY_FUTURE\\FJ_FLIE\\alice.txt")), StandardCharsets.UTF_8);
        List<String> words= Arrays.asList(cotents.split("\\PL+"));
        long count=0;
        for(String w:words){
            if(w.length()>12) count++;
        }
        //or user stream
        long count1=words.stream().filter(w->w.length()>12 ).count();

        System.out.println("---------count---------"+count);
        System.out.println("---------count1---------"+count1);
    }
    //1.2流的创建
    public static void creatStream() throws IOException{
        String cotents=new String(Files.readAllBytes(Paths.get("E:\\MY_FUTURE\\FJ_FLIE\\alice.txt")), StandardCharsets.UTF_8);
        //用Collection接口的.stream()或parallelStream()方法将任意结合转换成一个流（顺序流或并行流）

        //2.数组可以使用Stream.of()方法；使用 Arrays.stream(array,from.to)可以从数组
        // 中位于from（包括）和to（不包括）的元素中创建一个流
        Stream<String> words=Stream.of(cotents.split("\\PL+"));

        //3.创建不包含任何元素的流：
        Stream<String> words2=Stream.empty();

        //注java API中有大量的方法可以返回一个流；
        //pattern类有一个方法会按照一个正则表达式来分割一个字符对象；
        Stream<String> words3= Pattern.compile("\\PL+").splitAsStream(cotents);
        //静态的Files.lines会返回一个包含了文件中所有行的stream；
        Stream<String> words4=Files.lines(Paths.get("E:\\MY_FUTURE\\FJ_FLIE\\alice.txt"));
        words4.forEach(str-> System.out.println("---"+str));


        //流的转换会产生一个新的流，他的元素派生自另一个流中的元素
        //1.3 filter，map和flatMap方法；
        //1.filter:产生一个流，它包含当前流中所有满足断言条件的元素；
        Stream<String> words7=words4.filter(w->w.length()>12 );//将流words中的所有长度大于12的元素生成一个新流words7
        //2.map:产生一个流，它包含将mapper应用于当前流中所有元素产生的结果；
        Stream<String> words5=words4.map(s->s.substring(0,1));//将流words4中的所有元素取首字母并将结果产生新流words5
        Stream<String> words6=words4.map(String::toLowerCase);//将流words4中的所有元素转小写并将结果产生新流words6
        //3.flatMap:产生一个流，它是通过将mapper应用于当前流中所有元素所产生的结果连接到一起而获得的（注：这里每个结果都是一个流）；

    }

    //1.4抽取子流和连接流
    public static void stream_014(){
        //1.limit：产生一个流， 其中包含了当前流中最初的 maxSize 个元素。它在 n 个元素之后结束
        // （如果原来的流更那么就会在流结束时结束）。 这个方法对于裁剪无限流的尺寸会显得特别有用。
        Stream<Double> randoms = Stream .generate (Math::random).limit(100) ;//会产生一个包含 100 个随机数的流。
        //2.skip:产生一个流 ， 它的元素是当前流中除了前n个元素之外的所有元素。

        //3.concat:产生一个流， 它的元素是a的元素后面跟着b的元素。当然， 第一个流不应该是无限的， 否则第二个流永远都不会得到处理的机会。
        Stream<String> combined= Stream.concat(letters("Hello"), letters("Wor1d"));
        // Yields the stream ["H", "e", "l", "1", "o", "W", "o", "r", "l", "d"

    }

    //1.5其他流的转换
    public static void stream_015(){
        //1.Stream<T> distinct():产生一个流，包含当前流中所有不同的元素 。
        Stream<String> uniqueWords= Stream.of
                ("merrily", "merrily", "merrily", "gently") .distinct();// On1y one "merrily" is retained
        //2.Stream<T> sorted(Comparator<? super T> comparator)产生一个流，它的元素是当前流中的所有元素按照顺序排列的。
        Stream<String> longestFirst =Stream.of(cotents.split("\\PL+"))
                .sorted(Comparator.comparing (String::length).reversed());//根据字符串长度倒叙排列
        //3.Stream<T> peek(Consumer<? super T> action)：产生一个流，它与当前流中的元素相同 ，
        // 在获取其中每个元素时，会将其传递给action。
        Object[] powers= Stream.iterate(1.0, p -> p * 2)
                .peek(e -> System.out.println("Fetching" + e))//当实际访问一个元素时， 就会打印出来一条消息。
                                                                // 通过这种方式,你可以验证iterate返回的无限流
                                                                //是被惰性处理的。对于调试,你可以让peek调用一
                                                                //个你设置了断点的方法。
                .limit(20). toArray();
    }


    //1.6简单约简.约简是一种终结操作,它们会将流约简为可以在程序中使用的非流值
    public static void stream_016(){
        /*  Optional <T> max(Comparator<? super T> comparator)
            Optional <T> min(Comparator<? super T> comparator)
            分别产生这个流的最大元素和最小元素， 使用由给定比较器定义的排序规则，
             如果这 个流为空， 会产生一个空的Optional对象。 这些操作都是终结操作。*/
        Optional<String> largest = Stream.of(cotents.split("\\PL+"))
                .max(String::compareToIgnoreCase);
        /*  Optional<T> findFirst()
            Optional <T> findAny()
            分别产生这个流的第一个和任意一个元素，如果这个流为空，会产生一个空的Optional对象,这些操作都是终结操作*/
        Optional<String> startsWithQ = Stream.of(cotents.split("\\PL+"))
                .filter(s -> s.startsWith("Q")) . findFirst();
        /*	boolean anyMatch(Predicate<? super T> predicate)
            boolean allMatch(Predicate<? super T> predicate)
            boolean noneMatch(Predicate<? super T> predicate)
            分别在这个流中任意元素、 所有元素和没有任何元素匹配给定断言时返回 true。 这些操作都是终结操作。*/
        boolean aWordStartsWithQ = Stream.of(cotents.split("\\PL+"))
                .parallel()
                .anyMatch(s -> s .startsWith("Q"));

    }

    //1.7:Optional类型
    public static void stream_017(){

    }

    //1.8收集结果
    public static void stream_018(){
        /*void forEach(Consumer<? super T> action)
        在流的每个元素上闾用action 。 这是一种终结操作。*/

        /*Object[] toArray()
        <A> A[] toArray(IntFunction<A[]> generator)
        产生一个对象数组， 或者在将引用A[]::new传递给构造器时， 返回一个A类型的数组，这些操作都是终结操作。*/
        String[] result=  Stream.of(cotents.split("\\PL+"))
                .toArray(String[]::new);

        /*<R,A> R collect(Collector<? super T,A,R> collector)
         *使用给定的收集器来收集当前流中的元素。 Collectors类有用于多种收集器的T厂方法。 */

        //针对将流中的元素收集到另一个目标中， 有一个便捷方法collect可用， 它会接受—个 Collector接口的实例。
        // Collectors类提供了大扯用于生成公共收集器的工厂方法。 为了将流收集到列表或集中， 可以直接调用
        List<String> result1 = Stream.of(cotents.split("\\PL+"))
                .collect(Collectors.toList());
        //或
        Set<String> result2= Stream.of(cotents.split("\\PL+"))
                .collect(Collectors.toSet());
        //如果想要控制获得的集的种类， 那么可以使用下面的曲用：
        TreeSet<String> result3 = Stream.of(cotents.split("\\PL+"))
                . collect (Collectors. toCollection(TreeSet::new)) ;
        //假设想要通过连接操作来收集流中的所有宇符串。 我们可以调用
        String result4= Stream.of(cotents.split("\\PL+"))
                .collect(Collectors.joining());
        //如果想要在元素之间增加分隔符， 可以将分隔符传递给joining方法：
        String result5= Stream.of(cotents.split("\\PL+"))
                .collect(Collectors.joining(", "));
        //如果流中包含除字符串以外的其他对象， 那么我们需要现将其转换为字符串 ， 就像下面这样：
        String result6 = Stream.of(cotents.split("\\PL+"))
                .map(Object::toString) .collect(Collectors.joining(", "));
        //如果想要将流的结果约简为总和、 平均值、 最大值或最小值， 可以使用summarizing (Int|Long|Double)
        // 方法中的某一个。 这些方法会接受一个将流对象映射为数据的函数，同时， 这些方法会产生类型为
        // (Int|Long|Double)SummaryStatistics的结果， 同时计算总和 、 数最、 平均值、 最小值和最大值。
        IntSummaryStatistics summary = Stream.of(cotents.split("\\PL+"))
                . collect(Collectors.summarizingInt(String::length));
        double averageWordlength = summary.getAverage();//平均值
        double maxWordlength = summary.getMax();//最大值


    }

    //1.9 收集到映射表中
    public static void stream_019(){

    }


    //拆解单词成字符流
    public static Stream<String> letters(String s){
        List<String> result = new ArrayList<> ();
        for (int i = 0; i < s.length(); i++)
            result.add(s.substring(i, i + 1));
        return result.stream();
    }


}
